package petrus.components.scroll
{

	import com.greensock.TweenMax;
	import flash.display.BlendMode;
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import petrus.components.AbstractComponent;
	import petrus.components.events.ComponentEvent;



	public class AbstractScrollBar extends AbstractComponent implements IScrollBar
	{

		public var orientation:String;
		protected var _handler:Sprite;
		protected var _background:Sprite;
		protected var _arrowMinus:Sprite;
		protected var _arrowPlus:Sprite;
		private var _easing:Number = 2.1;
		private var _width:Number;
		private var _height:Number;
		private var _useArrows:Boolean;
		private var _enabled:Boolean;
		private var _contentArea:DisplayObject;
		private var _maskArea:DisplayObject;
		private var _updateHandler:Boolean;
		private var _isMouseDown:Boolean;
		private var _value:Number = 0;
		private var _valueInit:Number = 0;
		private var _valueTarget:Number = 0;
		private var _percent:Number = 0;

		private var _rangeScroll:Number;
		private var _maxValueScroll:Number;
		private var _minValueScroll:Number;
		private var _mouseClick:Number;
		private var _mouseWheelDelta:Number = 8;


		/**
		 * Constructor
		 *
		 * @param  __useArrows true if scrollbar uses arrows
		 */
		public function AbstractScrollBar(__useArrows:Boolean=true)
		{
			_useArrows = __useArrows;
			super();
		}


		/**
		 * set smooth factor
		 *
		 * @param  e valeur du smoothing
		 */
		public function set easing(e:Number):void
		{
			if (e < 1)
				e = 1
			_easing = e;
		}


		/**
		 * return the mouseWheel delta
		 *
		 * @return  _mouseWheelDelta
		 */
		public function get mouseWheelDelta():Number
		{
			return _mouseWheelDelta;
		}


		/**
		 * set the mouseWheel delta
		 *
		 * @param  __value the new mouseWheel delta
		 */
		public function set mouseWheelDelta(__value:Number):void
		{
			_mouseWheelDelta = Math.abs(__value);
		}


		/**
		 * return the current scroll ratio
		 *
		 * @return  the current scroll ratio
		 */
		public function get percent():Number
		{
			return _percent;
		}

		/**
		 * get the useArrows value
		 *
		 * @return the useArrows value
		 */
		public function get useArrows():Boolean
		{
			return _useArrows;
		}


		/**
		 * set the useArrows value
		 *
		 * @param __value the useArrow value
		 */
		public function set useArrows(__value:Boolean):void
		{
			_useArrows = __value;
		}

		/**
		 *
		 * @inheritDoc
		 */
		override public function destroy(__e:Event=null):void
		{
			super.destroy(__e);
			disable();

			while (numChildren)
				removeChildAt(0);
		}

		/**
		 * resize the scrollbar
		 *
		 * @param __width the width
		 * @param __height the height
		 */
		override public function resize(__width:Number=0, __height:Number=0):void
		{
			if (__width > __height)
				orientation = ScrollBarOrientation.HORIZONTAL;
			else
				orientation = ScrollBarOrientation.VERTICAL;

			_initSize(__width , __height);
			_update();

			forceRender();
		}

		/**
		 *
		 * @param	percent
		 * @param	useEasing
		 */
		public function forcePercentPos(p_percent:Number, __useEasing:Boolean=true):void
		{
			if (p_percent < 0)
				p_percent = 0;
			if (p_percent > 1)
				p_percent = 1;

			_valueTarget = _minValueScroll + p_percent * _rangeScroll;
			
			if (!__useEasing)
			{				
				_valueInit = _value = _valueTarget;
				//_percent = p_percent;				
				_mouseClick = mouseY;	
			}

			_render()
			//_handler.addEventListener(Event.ENTER_FRAME , _render);		
		}

		
		protected function forceRender():void
		{
			// ON REINITIALISE LES BONNES VALEUR
			_valueTarget = _value = _minValueScroll + (_maxValueScroll - _minValueScroll) * _percent;
			// PUIS ON FORCE LE RENDER
			_percent = 0

			if (!_enabled)
				return

					//_handler.addEventListener(Event.ENTER_FRAME , _render);
			_render();
		}

		public function enable():void
		{
			if (!_enabled)
			{
				//trace("[AbstractScrollBar.enable] ");
				_enabled = true;
				_handler.alpha = 1				
				_handler.visible = true;			
				_background.visible = true;

				_handler.addEventListener(MouseEvent.MOUSE_DOWN, _onMouseEvent);
				stage.addEventListener(MouseEvent.MOUSE_UP, _onMouseEvent);
				_background.addEventListener(MouseEvent.MOUSE_DOWN, _onBgClick);

				if (_useArrows)
				{
					if (orientation == ScrollBarOrientation.HORIZONTAL)
						_handler.x = _arrowPlus.x + _arrowPlus.width;
					if (orientation == ScrollBarOrientation.VERTICAL)
						_handler.y = _arrowPlus.y + _arrowPlus.height;
					_arrowMinus.visible = true;
					_arrowMinus.name = "arrowMinus";
					_arrowMinus.addEventListener(MouseEvent.CLICK, _onArrowClick);

					_arrowPlus.visible = true;
					_arrowPlus.name = "arrowPlus";
					_arrowPlus.addEventListener(MouseEvent.CLICK, _onArrowClick);
				}
			}
		}


		public function disable():void
		{
			
			_handler.alpha = .5
			/*
			_handler.visible = false;
			_background.visible = false;
			*/
			if (_enabled)
			{
				//trace("[AbstractScrollBar.disable] ");
				_enabled = false;
				
				stage.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_UP));
				//_handler.removeEventListener(Event.ENTER_FRAME, _render);
				_handler.removeEventListener(MouseEvent.MOUSE_DOWN, _onMouseEvent);
				stage.removeEventListener(MouseEvent.MOUSE_MOVE, _onMouseEvent);
				stage.removeEventListener(MouseEvent.MOUSE_UP, _onMouseEvent);
				_background.removeEventListener(MouseEvent.MOUSE_DOWN, _onBgClick);
				stage.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_UP));
				if (useArrows)
				{
					_arrowMinus.visible = false;
					_arrowMinus.removeEventListener(MouseEvent.CLICK , _onArrowClick);
					_arrowPlus.visible = false
					_arrowPlus.removeEventListener(MouseEvent.CLICK , _onArrowClick);
				}
			}
		}


		/**
		 * set the displayobject to scroll & the mask
		 *
		 * @param contentArea the displayobject to scroll
		 * @param mask the mask displayobject
		 */
		public function setContent(__contentArea:DisplayObject, __mask:DisplayObject):void
		{
			_updateHandler = true;
			_contentArea = __contentArea;
			_maskArea = __mask;
			_update();
		}


		/**
		 * update the scroll value from mousewheel
		 *
		 * @param	__delta the mousewheel delta
		 */
		public function renderWheel(__delta : Number):void
		{
			if (!_enabled)
				return;
			
			_valueTarget += __delta * mouseWheelDelta;
			//_handler.addEventListener(Event.ENTER_FRAME , _render);
			_render();
			
		}
		
		public function get enabled():Boolean
		{
			return _enabled = false;
		}

		
		/**
		 * to implement in order to custom the background design
		 */
		protected function _addBackground():void
		{
			_background = drawSprite(new Rectangle(0, 0, properties.width, properties.height), 0xFFFFFF , 0);
			addChild(_background);
		}


		/**
		 * to implement in order to custom the handler design
		 */
		protected function _addHandler():void
		{
			//_handler = drawSprite(new Rectangle(0, 0, 1, 50), 0xFFFFFF,1);
			_handler = new HandlerAsset()
			_handler.buttonMode = true;
			addChild(_handler);
			
		}


		/**
		 * to implement in order to custom the arrows design
		 */
		protected function _addArrows():void
		{
			if (useArrows)
			{
				_arrowMinus = drawSprite(new Rectangle(0, 0, _width, _width), 0xFF0000);
				_arrowMinus.buttonMode = true;
				_arrowMinus.addEventListener(MouseEvent.CLICK , _onArrowClick);
				addChild(_arrowMinus);

				_arrowPlus = drawSprite(new Rectangle(0, 0, _width, _width), 0xFF0000);
				_arrowPlus.buttonMode = true;
				_arrowPlus.addEventListener(MouseEvent.CLICK , _onArrowClick);
				addChild(_arrowPlus);
			}
		}

		override protected function _build(params:*=null, optionals:*=null):void
		{
			properties.width = 10;
			properties.height = 150;

			_addBackground();
			_addHandler();
			_addArrows();
		}


		override protected function _init(__e:Event=null):void
		{
			super._init(__e);
		}


		/**
		 *
		 * @param	width
		 * @param	height
		 */
		protected function _initSize(__width:Number, __height:Number):void
		{
			properties.width = _width = Math.round(__width);
			properties.height = _height = Math.round(__height);

			_background.width = _width;
			_background.height = _height;

			//_value = 0

			if (orientation == ScrollBarOrientation.VERTICAL)
			{
				//_valueInit = _valueTarget = _value = _posY
				if (_useArrows)
				{
					_background.height = Math.round(_height - 2 * (_arrowMinus.height + 1));
					_arrowMinus.y = 0;
					_background.y = _arrowPlus.y + _arrowPlus.height + 1;
					_arrowMinus.y = Math.round(_background.y + _background.height + 1 );
				}
			}
			else if (orientation == ScrollBarOrientation.HORIZONTAL)
			{
				//_valueInit = _valueTarget = _value = _posX
				if (_useArrows)
				{
					_background.width = Math.round(_width - 2 * (_arrowMinus.width + 1));
					_arrowMinus.x = Math.round(_background.x + _width + 1 - _arrowMinus.width );

					_arrowMinus.x = Math.round(- 4 - _arrowMinus.width )
					_arrowMinus.rotation = -90

					_arrowMinus.rotation = -90
					_arrowMinus.y = _arrowMinus.y = Math.round(_background.y  +  _background.height   / 2);
				}
			}
		}

		protected function _update():void
		{
			_updateHandlerSize();
			_updateScrollValues();
		}

		protected function _updateHandlerSize():void
		{
			var size:Number;

			if (this.orientation == ScrollBarOrientation.VERTICAL)
			{
				if (_updateHandler)
				{
					size = (_maskArea.height / _contentArea.height) * _height;
					if (size > .85 * _background.height)
						size = .85 * _background.height;
				}
				else
				{
					size = _handler.height;
				}

				_rangeScroll = _background.height - Math.floor(size);
			}
			if (this.orientation == ScrollBarOrientation.HORIZONTAL)
			{
				if (_updateHandler)
				{
					size = (_maskArea.width / _contentArea.width) * width;
					if (size > .85 * _background.width)
						size = .85 * _background.width;
				}
				else
					size = _handler.width;


				_rangeScroll = _background.width - size;
			}


			//trace("[AbstractScrollBar._updateHandlerSize] _rangeScroll "+_rangeScroll);
			//_redrawHandler(size);
		}

	
		private function _updateScrollValues():void
		{
			if (orientation == ScrollBarOrientation.HORIZONTAL)
				_minValueScroll = _background.x;
			if (orientation == ScrollBarOrientation.VERTICAL)
				_minValueScroll = _background.y;

			_maxValueScroll = _minValueScroll + _rangeScroll;
		}
		
		private function _onBgClick(e:MouseEvent):void
		{
			var percent:Number;
			if (orientation == ScrollBarOrientation.HORIZONTAL)
				percent = _background.mouseX * _background.scaleX / _background.width;
			if (orientation == ScrollBarOrientation.VERTICAL)
				percent = _background.mouseY * _background.scaleY / _background.height;

			forcePercentPos(percent);
			_render();
		}

		private function _onArrowClick(__e:MouseEvent):void
		{
			var delta:Number;
			if (__e.currentTarget.name == "arrowPlus")
				delta = -5;
			if (__e.currentTarget.name == "arrowMinus")
				delta = 5;

			_valueTarget += delta;

			_render();
		}


		/**
		 * Mouse Handler (or stage)Events Handler
		 * @param e MouseEvent
		 */
		private function _onMouseEvent(__e:MouseEvent):void
		{
		
			//trace("[AbstractScrollBar._onMouseEvent] "+__e.type);
			switch (__e.type)
			{
				case MouseEvent.MOUSE_MOVE:
					if (_enabled && !_handler.hasEventListener(Event.ENTER_FRAME))
					{
						//trace("[AbstractScrollBar._onMouseEvent] MOUSE_MOVE _handler.addEventLi");
						_handler.addEventListener(Event.ENTER_FRAME, _render);
					}
					break;

				case MouseEvent.MOUSE_DOWN:
					_valueInit = _value;
					if (orientation == ScrollBarOrientation.HORIZONTAL)
						_mouseClick = this.mouseX;
					else if (orientation == ScrollBarOrientation.VERTICAL)
						_mouseClick = this.mouseY;

						//trace("[AbstractScrollBar._onMouseEvent] MOUSE_DOWN _handler.addEventLi");
					_isMouseDown = true;
					stage.addEventListener(MouseEvent.MOUSE_MOVE, _onMouseEvent);
					break;

				case MouseEvent.MOUSE_UP:
					_isMouseDown = false;
					stage.removeEventListener(MouseEvent.MOUSE_MOVE, _onMouseEvent);
					break;
			}
		}


		/**
		 * update the scroll handler position
		 *
		 */
		public function _render(__e:Event=null):void
		{
			if (_isMouseDown)
				_valueTarget = _valueInit + _delta;

			if (_valueTarget < _minValueScroll)
				_valueTarget = _minValueScroll;

			if (_valueTarget > _maxValueScroll)
				_valueTarget = _minValueScroll + _rangeScroll;
			
			// TO LIMIT SPEED
			var delta : Number = (_valueTarget - _value);
			if(delta >150) delta = 150
			_value += delta / _easing;

			var percentNext:Number = (_value - _minValueScroll) / (_maxValueScroll - _minValueScroll);
			
			//trace("[AbstractScrollBar._render] "+_value , _valueTarget);
			
			if (Math.round(percentNext*1000) != Math.round(percent*1000))
			{
				_percent = percentNext;
				if (orientation == ScrollBarOrientation.HORIZONTAL)
					_handler.x = _value;
				if (orientation == ScrollBarOrientation.VERTICAL)
					_handler.y = Math.round(_value);
				dispatchEvent(new ComponentEvent(ComponentEvent.CHANGE));
			}
			else
			{
			//	_handler.removeEventListener(Event.ENTER_FRAME, _render);
			}
		}

		private function get _delta():Number
		{
			var delta:Number = 0;
			switch (orientation)
			{
				case ScrollBarOrientation.HORIZONTAL:
					delta = this.mouseX - _mouseClick;
					break;

				case ScrollBarOrientation.VERTICAL:
					delta = this.mouseY - _mouseClick;
					break;
			}

			return delta;
		}
		
		public function get easing():Number 
		{
			return _easing;
		}
		
	
	}
}